#pragma once

#include <Gluck.h>
#include <string>
#include "utf8/utf8.h"
#include <vector>

namespace liba {

/** Stores UTF-8 data and allows conversions to ANSI (losing data) or UTF-16 WString */
class Utf8String
{
public:
	Utf8String()
	{ }

	Utf8String(const char* src)
		: buffer(src)
	{ }

	Utf8String(const Utf8String& rhs)
		: buffer(rhs.buffer)
	{ }

	const Utf8String& operator=(const Utf8String& rhs)
	{
		this->buffer = rhs.buffer;
		return *this;
	}

	static Utf8String FromXmlChars(unsigned char* xmlChars)
	{
		return Utf8String((const char*)xmlChars);
	}

	const char* c_str() const { return buffer.c_str(); }
	size_t size() const { return buffer.size(); }

	std::string::const_iterator begin() const { return buffer.begin(); }
	std::string::const_iterator end() const { return buffer.end(); }

private:
	std::string buffer;
};

/** ConverterTraits specializations for Utf8String support conversions to ansi or unicode. */
namespace converter
{

template<>
struct ConverterTraits<wchar_t, Utf8String>
{
public:
	struct Buffer
	{
		const wchar_t* begin() 
		{ 
			if (buf.empty())
				return 0;

			return &buf[0];
		}
		const wchar_t* end() 
		{ 
			if (buf.empty())
				return 0;

			return &buf[0] + buf.size();
		}

		bool convert(const Utf8String& value)
		{
			if (sizeof(wchar_t) == sizeof(unsigned short))
				utf8::utf8to16(value.begin(), value.end(), std::back_inserter(buf));
			else if (sizeof(wchar_t) == sizeof(int))
				utf8::utf8to32(value.begin(), value.end(), std::back_inserter(buf));
			else
				THROW(Gluck(__FUNCTION__, "Invalid size of wchar_t"));

			return true;
		}
	private:
		std::vector<wchar_t> buf;
	};
};

template<>
struct ConverterTraits<char, Utf8String>
{
public:
	struct Buffer
	{
		const char* begin() { return str->c_str(); }
		const char* end() { return str->c_str() + str->size(); }

		bool convert(const Utf8String& value)
		{
			this->str = &value;
			return true;
		}
	private:
		const Utf8String* str;
	};
};

} //namespace converter


} // namespace liba